#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__
#include<iostream>
#include<vector>
#include"../mqcommon/mq_msg.pb.h"
#include"../mqcommon/mq_helper.hpp"

namespace xiang11mq
{
//交换机路由管理 接口类
class Router
{
public:
    //判断binding_key是否合法
    static bool isLegalBindingKey(const std::string &binding_key)
    {
        //* 可以匹配任意一个单词(不是字母)
        //# 可以匹配任意0个或多个单词(不是字母)(剩下全部)
        //1.判断是否有非法字符 合法字符(a ~ z, A ~ Z, 0 ~ 9, _, ., *, #)
        for(auto &ch : binding_key)
        {
            if( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
            ||  (ch >= '0' && ch <= '9') || (ch == '.' || ch == '_') || (ch == '*' || ch == '#'))
            {
                continue;
            }
            DLOG("binding_key不合法 %s", binding_key.c_str());
            return false;
        }
        //2. *和# 必须独立存在    
        std::vector<std::string> sub_words;
        StrHelper::split(binding_key, ".", sub_words);
        for(auto &word : sub_words)
        {
            if(word.size() > 1 && (word.find(".") != std::string::npos ||
             word.find("#") != std::string::npos))
            {
                DLOG("*和# 必须独立存在 %s", word.c_str());
                return false;
            }
        }

        //3. #通配符两边不能出现单词
        for(int i = 1; i < sub_words.size(); i ++)
        {
            if( (sub_words[i] == "#" && sub_words[i - 1] == "*") || 
                (sub_words[i] == "*" && sub_words[i - 1] == "#") ||
                (sub_words[i] == "#" && sub_words[i - 1] == "#"))
            {
                DLOG("* # 不能连续出现sub_words[%d]: %s, sub_words[%d]: %s",
                i - 1, sub_words[i- 1].c_str(), i , sub_words[i].c_str());
                return false;
            }
        }

        return true;
    }
    //判断routing_key是否合法
    static bool isLegalRoutingKey(const std::string &routing_key)
    {
        //routing_key 只需要判断是否有非法字符 合法字符(a ~ z, A ~ Z, 0 ~ 9, _, .)
        for(auto &ch : routing_key)
        {
            if( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
            ||  (ch >= '0' && ch <= '9') || (ch == '.' || ch == '_'))
            {
                continue;
            }
            DLOG("routing_key不合法 %s", routing_key.c_str());
            return false;
        }

        return true;
    }
    //路由
    static bool route(ExchangeType type, const std::string &routing_key, const std::string &binding_key)
    {
        if(type == ExchangeType::DIRECT)
        {
            //直接交换模式
            return routing_key == binding_key;
        }
        else if(type == ExchangeType::FANOUT)
        {
            //广播模式
            return true;
        }
        else
        {
            //主题交换模式 要进行模式匹配 eg: news.# & news.music.pop
            //1.将binding_key与routing_key分割 得到各个的单词数组
            std::vector<std::string> bkeys, rkeys;
            int n_bkey = StrHelper::split(binding_key, ".", bkeys);
            int n_rkey = StrHelper::split(routing_key, ".", rkeys);
            //2.定义标记数组 dp[0][0] = 1 其余0
            std::vector<std::vector<bool>> dp(n_bkey + 1, std::vector<bool>(n_rkey + 1, false));
            dp[0][0] = true; 
            //3.如果binding_key 以#起始 将#对应的第0列置为1
            for(int i = 1; i <= bkeys.size(); i ++)
            {
                if(bkeys[i - 1] == "#")
                {
                    dp[i][0] = true;
                    continue;
                }
                break;
            }

            //4.使用 routingkey 和 bindingkey 每个单词进行匹配并标记数组
            for(int i = 1; i <= n_bkey; i ++)
            {
                for(int j = 1; j <= n_rkey; j ++)
                {
                    //如果当前bkey是个*，或者两个单词相同，表示单词匹配成功，则从左上方继承结果
                    if(bkeys[i - 1] == rkeys[j - 1] || bkeys[i - 1] == "*")
                    {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                    //如果当前bkey是个#，则需要从左上，左边，上边继承结果
                    else if(bkeys[i - 1] == "#")
                    {
                        dp[i][j] = dp[i - 1][j - 1] | dp[i - 1][j] | dp[i][j - 1];
                    }
                }
            }
            return dp[n_bkey][n_rkey];
        }
    }

};
   
}


#endif